package com.gitee.wsl.api

import kotlinx.atomicfu.atomic
import kotlin.experimental.or

interface Flag<N:Number> {

    fun getFlag(): N

    companion object{

        fun <N:Number, E : Flag<N>> toFlag(vararg values: E): N = when (values.first().getFlag()) {
            is Byte -> toFlag(*values)
            is Short -> toFlag(*values)
            is Int -> toFlag(*values)
            is Long -> toFlag(*values)
            else -> throw IllegalArgumentException("Unsupported Flag type")
        }


        fun <E : Flag<Byte>> toFlag(enumSet: Array<E>): Byte  {
            var value = 0.toByte()
            for (flag in enumSet) {
                value = value or flag.getFlag()
            }
            return value
        }

        fun <E : Flag<Short>> toFlag(enumSet: Array<E>): Short  {
            var value = 0.toShort()
            for (flag in enumSet) {
                value = value or flag.getFlag()
            }
            return value
        }

        fun <E : Flag<Int>> toFlag(enumSet: Array<E>): Int  {
            var value = 0
            for (flag in enumSet) {
                value = value or flag.getFlag()
            }
            return value
        }

        fun <E : Flag<Long>> toFlag(enumSet: Array<E>): Long  {
            var value = 0L
            for (flag in enumSet) {
                value = value or flag.getFlag()
            }
            return value
        }


//        fun <E : Flag> longToEnumSet(flags: Long, values: Array<E>): Set<E> {
//            require(values.isNotEmpty()) { "Empty FlagEnum" }
//            val flagList = mutableSetOf<E>()
//            for (value in values) {
//                if ((flags and value.getFlag()) != 0L) {
//                    flagList.add(value)
//                }
//            }
//            return flagList
//        }
    }
}


interface FlagGenerator<T:Number> {
    fun next():T

    companion object{
        fun longFlagGenerator():LongFlagGenerator = LongFlagGenerator()
        fun intFlagGenerator():IntFlagGenerator = IntFlagGenerator()
        fun byteFlagGenerator():ByteFlagGenerator = ByteFlagGenerator()
        fun shortFlagGenerator():ShortFlagGenerator = ShortFlagGenerator()
    }
}

class LongFlagGenerator(init:Int = 0): FlagGenerator<Long>{
    val flag = atomic(init)

    override fun next():Long{
        if(flag.value >= Long.SIZE_BITS) throw IllegalArgumentException("flag is overflow")
        val shlCount = flag.incrementAndGet()
        return 1L shl shlCount
    }
}

class IntFlagGenerator(init:Int= 0): FlagGenerator<Int>{
    val flag = atomic(init)

    override fun next():Int{
        if(flag.value >= Int.SIZE_BITS) throw IllegalArgumentException("flag is overflow")
        val shlCount = flag.incrementAndGet()
        return 1 shl shlCount
    }
}

class ByteFlagGenerator(init:Int = 0): FlagGenerator<Byte>{
    val flag = atomic(init)

    override fun next():Byte{
        if(flag.value >= Byte.SIZE_BITS) throw IllegalArgumentException("flag is overflow")
        val shlCount = flag.incrementAndGet()
        return (1 shl shlCount).toByte()
    }
}

class ShortFlagGenerator(init:Int = 0): FlagGenerator<Short>{
    val flag = atomic(init)

    override fun next():Short{
        if(flag.value >= Short.SIZE_BITS) throw IllegalArgumentException("flag is overflow")
        val shlCount = flag.incrementAndGet()
        return (1 shl shlCount).toShort()
    }
}